#ifndef _Event_H_
#define _Event_H_

//
// Event.h
//
// Created by TB on 11/17/11.
// Copyright 2011 BNL. All rights reserved.
//

#include <vector>

#ifndef __CINT__
#include <boost/shared_ptr.hpp>
#endif

#include <TClonesArray.h>
#include <TObject.h>
#include <TVector3.h>

#include "tppmc/Particle.h"
#include "tppmc/PartonDistribution.h"
namespace tppmc {
   
   class Distributions;
   class FragmentationFunction;
   
   /**
    An event, containing partons involved in the hard scattering, and hadrons
    produced from their fragmentation.
   */
   class Event : public TObject {
      
   public:
      
      /**
       Destructor.
       */
      virtual ~Event() { }
      
      /**
       Returns the PYTHIA process ID the generated the event.
       */
      virtual int Process() const { return mProcessId; }
      
      /**
       Returns the momentum fraction carried by the first parton
       in the hard interaction.
       */
      virtual double PartonX1() const { return mScatter.at(0).x; }
      
      /**
       Returns the momentum fraction carried by the second parton
       in the hard interaction.
       */
      virtual double PartonX2() const { return mScatter.at(1).x; }
      
      /**
       Returns the scale of the scattering process.
       */
      virtual double QSquared() const { return mQSquared; }
      
      /**
       Returns the transvesre momentum of the hard subprocess
       in the rest frame of the hard interaction.
       */
      virtual double PartonPt() const { return 0.; }
      
      virtual double SiversWeight1() const { return 0.; }
      virtual double SiversWeight2() const { return 0.; }
      virtual double SiversSpinFactor1() const { return 0.; }
      virtual double SiversSpinFactor2() const { return 0.; }
      
      /**
       Returns the (x, y, z) coordinates of the collision
       point in the laboratory frame.
       */
      virtual TVector3 Vertex() const { return TVector3(); }
      
      /**
       Returns the spin (-1, 0 or +1) of the first beam.
       */
      virtual short Spin1() const { return 0; }
      
      /**
       Returns the spin (-1, 0 or +1) of the second beam.
       */
      virtual short Spin2() const { return 0; }
      
      /**
       Returns the phi rotation applied to the event.
       */
      virtual double Rotation() const { return 0.; }
      
      /** Set the event plane rotation to apply to all particles */
      virtual void SetRotation(double radians) { mRotation = radians; }
      
      /**
       Returns the list of partons in the event.
       */
      virtual std::vector<tppmc::Parton*> Partons() const;
      
      /**
       Returns the list of hadrons in the event.
       */
      virtual std::vector<tppmc::Hadron*> Hadrons() const;
      
      /**
       Fragment all partons in the event record into hadrons using
       the specified fragmentation function.
       Returns the number of new hadrons generated.
       */
      virtual int Fragment(FragmentationFunction&);
      
      /**
       Add a parton to the parton list.
       Returns the new size of the parton list.
       */
      virtual unsigned AddParton(const Parton&);
      
      /**
       Add a hadron to the hadron list.
       Returns the new size of the hadron list.
       */
      virtual unsigned AddHadron(const Hadron&);
      
      /**
       Private constructor to force use of EventFactory.
       Constructs an event using the current state of TPythia6.
       Optionally provide a phi angle (between 0 and 2pi in radians) by
       which to rotate the event coordinates from the generated plane.
       \remark public for debug
       */
      Event(double rotation = 0., double etamin = -1000.,
            double etamax = 1000., double minpt = 0.);
      
      /** Returns the fragmentation multiplicity of the nth parton */
      unsigned Multiplicity(unsigned n) const;
      
      /**
       Set the event contents from the current state of TPythia6.
       */
      void Update(Distributions&);
      
      /**
       For debug
       */
      Hadron HadronSum(int group) const;
      
//   protected:
      
      /**
       Populate the parton and hadron lists from the
       current state of PYTHIA.
       */
      void FillParticles(Distributions&);
      
      /** Fragment a single parton. Return the number of hadrons is produces */
      virtual int FragmentParton(Parton&, FragmentationFunction&);
      
#ifndef __CINT__
      typedef boost::shared_ptr<PartonDistribution> Pdf;
      double ComputeSiversWeight(const Parton&, Distributions&);
      double ComputeSiversSpinFactor(const Parton&);
      double ComputeTransverseSpin(const Parton&, Distributions&);
#endif
      void ComputeCentreOfMassEnergy();
      
      Int_t mProcessId;
      Double32_t mQSquared;
      Double32_t mPartonPt;
      Double32_t mCentreOfMassEnergy;
      std::vector<Parton> mScatter; ///< Partons from each beam at the hard
                                    ///< scattering. Always has 2 elements,
                                    ///< the first from the +z beam, the second
                                    ///< from the -z beam.
      Double32_t mRotation;
      double mEtaMin; //!
      double mEtaMax; //!
      double mMinPt; //!
      
      TClonesArray mPartons; ///< Parton after scattering/radiation, which
                             ///< are passed to fragmentation
      TClonesArray mHadrons; ///< Final-state particles from fragmentation
      
      friend class EventFactory;
      
      ClassDef(tppmc::Event, 1)
   };
   
   
   /**
    \todo Move event-building code to EventFactory.
    Build Event objects.
    */
   class EventFactory : public TObject {
      
   public:
      
      /**
       Use the specified fragmentation function to fragment
       partons into hadrons when building events.
       */
      EventFactory(FragmentationFunction* = NULL) { }
      
      virtual ~EventFactory() { }
      
      Event* Create(double rotation = 0.);
      
      ClassDef(tppmc::EventFactory, 1)
   };
   
} // namespace tppmc

#endif
